/*
 * Engine.cpp - Engine Control Unit dialog
 *
 * Copyright (C) 2008-2010 Comer352l
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "EngineDialog.h"


EngineDialog::EngineDialog(QWidget *parent, AbstractDiagInterface *diagInterface, QString language) : ControlUnitDialog(tr("Engine Control Unit"), diagInterface, language)
{
    this->setParent(parent);
    // *** Initialize global variables:
        this->setGeometry(QRect(0,0,798,498));
        _content_DCs = NULL;
	_content_MBsSWs = NULL;
	_content_Adjustments = NULL;
        _mode = NO_mode;	// we start in no mode
	// Show information-widget:
        _infoWidget = new CUinfo_Engine();
	setInfoWidget(_infoWidget);
	_infoWidget->show();
        // Setup functions:
        QPushButton *pushButton = addFunction(1,tr("&Diagnostic Codes"), QIcon(QString::fromUtf8(":/buttons/res/warning.png")));
        pushButton->setChecked(true);
        connect( pushButton, SIGNAL( clicked() ), this, SLOT( DCs() ) );
        pushButton = addFunction(2,tr("&Measuring Blocks"), QIcon(QString::fromUtf8(":/buttons/res/systemmonitor.png")));
        connect( pushButton, SIGNAL( clicked() ), this, SLOT( measuringblocks() ) );
        pushButton = addFunction(3,tr("&Adjustments"), QIcon(QString::fromUtf8(":/buttons/res/configure.png")));
        connect( pushButton, SIGNAL( clicked() ), this, SLOT( adjustments() ) );
        pushButton = addFunction(4,tr("System &Tests"), QIcon(QString::fromUtf8(":/freessm/res/klaptop.png")));
        connect( pushButton, SIGNAL( clicked() ), this, SLOT( systemoperationtests() ) );
        _clearMemory_pushButton = addFunction(5,tr("Clear Memory"), QIcon(QString::fromUtf8(":/freessm/res/eraser.png")));
        connect( _clearMemory_pushButton, SIGNAL( clicked() ), this, SLOT( clearMemory() ) );
	// Load/Show Diagnostic Code content:
        //_content_DCs = new CUcontent_DCs_engine();
        //setContentWidget(tr("Diagnostic Codes:"), _content_DCs);
        //_content_DCs->show();
	// Make GUI visible
	this->show();
	// Connect to Control Unit, get data and setup GUI:
	setup();
}


void EngineDialog::setup()
{
	QString sysdescription = "";
	std::string ROM_ID = "";
	QString VIN = "";
	bool supported = false;
	bool testmode = false;
	bool enginerunning = false;
	std::vector<mb_dt> supportedMBs;
	std::vector<sw_dt> supportedSWs;
        //int supDCgroups = 0;
	// ***** Connect to Control Unit *****:
	// Create Status information message box for CU initialisation/setup:
        myProgressbar initstatusmsgbox(0,tr("Connecting to Engine Control Unit... Please wait !"));
        initstatusmsgbox.start();
	// Try to establish CU connection:
	SSMprotocol::CUsetupResult_dt init_result = probeProtocol(SSMprotocol::CUtype_Engine);
	if ((init_result == SSMprotocol::result_success) || (init_result == SSMprotocol::result_noOrInvalidDefsFile) || (init_result == SSMprotocol::result_noDefs))
	{
		// Update status info message box:
                initstatusmsgbox.setText(tr("Processing Control Unit data... Please wait !"));
		// Query ROM-ID:
		ROM_ID = _SSMPdev->getROMID();
		if (!ROM_ID.length())
			goto commError;
		// Query system description:
		if (!_SSMPdev->getSystemDescription(&sysdescription))
		{
			std::string SYS_ID = _SSMPdev->getSysID();
			if (!SYS_ID.length())
				goto commError;
			sysdescription = tr("unknown");
			if (SYS_ID != ROM_ID)
				sysdescription += " (" + QString::fromStdString(SYS_ID) + ")";
		}
		// Display system description:
		_infoWidget->setEngineTypeText(sysdescription);
		// Display ROM-ID:
		_infoWidget->setRomIDText( QString::fromStdString(ROM_ID) );
		if (init_result == SSMprotocol::result_success)
		{
			// Number of supported MBs / SWs:
			if ((!_SSMPdev->getSupportedMBs(&supportedMBs)) || (!_SSMPdev->getSupportedSWs(&supportedSWs)))
				goto commError;
			_infoWidget->setNrOfSupportedMBsSWs(supportedMBs.size(), supportedSWs.size());
			// OBD2-Support:
			if (!_SSMPdev->hasOBD2system(&supported))
				goto commError;
			_infoWidget->setOBD2Supported(supported);
			// Integrated Cruise Control:
			if (!_SSMPdev->hasIntegratedCC(&supported))
				goto commError;
			_infoWidget->setIntegratedCCSupported(supported);
			// Immobilizer:
			if (!_SSMPdev->hasImmobilizer(&supported))
				goto commError;
			_infoWidget->setImmobilizerSupported(supported);
			// Update status info message box:
                        initstatusmsgbox.setText(tr("Reading Vehicle Ident. Number... Please wait !"));
			// Query and output VIN, if supported:
			if (!_SSMPdev->hasVINsupport(&supported))
				goto commError;
			if (supported)
			{
				if (!_SSMPdev->getVIN(&VIN))
					goto commError;
			}
			_infoWidget->setVINinfo(supported, VIN);
			// Check if we need to stop the automatic actuator test:
			if (!_SSMPdev->hasActuatorTests(&supported))
				goto commError;
			if (supported)
			{
				// Update status info message box:
                                initstatusmsgbox.setText(tr("Checking system status... Please wait !"));
				// Query test mode connector status:
				if (!_SSMPdev->isInTestMode(&testmode)) // if actuator tests are available, test mode is available, too...
					goto commError;
				if (testmode)	// wenn ECU im Testmodus
				{
					// Check that engine is not running:
					if (!_SSMPdev->isEngineRunning(&enginerunning)) // if actuator tests are available, MB "engine speed" is available, too...
						goto commError;
					if (!enginerunning)
					{
						// Update status info message box:
                                                initstatusmsgbox.setText(tr("Stopping actuators... Please wait !"));
						// Stop all actuator tests:
						if (!_SSMPdev->stopAllActuators())
							goto commError;
					}
				}
			}
			// "Clear Memory"-support:
			if (!_SSMPdev->hasClearMemory(&supported))
				goto commError;
			_clearMemory_pushButton->setEnabled(supported);
			// Update and close status info:
                        myMessage message(0);
                        message.exec(3,tr("Control Unit initialisation successful !"));
		}
		else
		{
			// "Clear Memory"-support:
			_clearMemory_pushButton->setEnabled(false);
			// Close progress dialog:
                        initstatusmsgbox.stop();
			// Show error message:
			QString errtext;
			if (init_result == SSMprotocol::result_noOrInvalidDefsFile)
			{
				errtext = tr("Error:\nNo valid definitions file found.\nPlease make sure that FreeSSM is installed properly.");
			}
			else if (init_result == SSMprotocol::result_noDefs)
			{
				errtext = tr("Error:\nThis control unit is not yet supported by FreeSSM.\nFreeSSM can communiate with the control unit, but it doesn't have the necessary data to provide diagnostic operations.\nIf you want to contribute to the the project (help adding defintions), feel free to contact the authors.");
			}
                        myMessage message(0);
                        message.exec(0,errtext);
			// Exit CU dialog:
                        close();
		}
	}
	else // All other errors
            goto commError;
	return;

commError:
        initstatusmsgbox.stop();
        communicationError();
}


void EngineDialog::DCs()
{
	bool ok = false;
	int DCgroups = 0;
	if (_mode == DCs_mode) return;
	// Show wait-message:
        myProgressbar waitmsgbox(0,tr("Switching to Diagnostic Codes... Please wait !"));
        waitmsgbox.start();
	// Save content settings:
	saveContentSettings();
	// Create, setup and insert new content-widget:
        _content_DCs = new CUcontent_DCs_engine();
	setContentWidget(tr("Diagnostic Codes:"), _content_DCs);
	_content_DCs->show();
	ok = _content_DCs->setup(_SSMPdev);
	// Start DC-reading:
	if (ok)
		ok = _SSMPdev->getSupportedDCgroups(&DCgroups);
		if (ok && DCgroups != SSMprotocol::noDCs_DCgroup)
			ok = _content_DCs->startDCreading();
	// Get notification, if internal error occures:
	if (ok)
		connect(_content_DCs, SIGNAL( error() ), this, SLOT( close() ) );
	// Save new mode:
	_mode = DCs_mode;
	// Close wait-message:
        waitmsgbox.stop();;
	// Check for communication error:
	if (!ok)
		communicationError();
}


void EngineDialog::measuringblocks()
{
	bool ok = false;
	if (_mode == MBsSWs_mode) return;
	// Show wait-message:
        myProgressbar waitmsgbox(0,tr("Switching to Measuring Blocks... Please wait !"));
        waitmsgbox.start();
	// Save content settings:
	saveContentSettings();
	// Create, setup and insert new content-widget:
	_content_MBsSWs = new CUcontent_MBsSWs(_MBSWsettings);
	setContentWidget(tr("Measuring Blocks:"), _content_MBsSWs);
	_content_MBsSWs->show();
	ok = _content_MBsSWs->setup(_SSMPdev);
	if (ok)
		ok = _content_MBsSWs->setMBSWselection(_lastMBSWmetaList);
	// Get notification, if internal error occures:
	if (ok)
		connect(_content_MBsSWs, SIGNAL( error() ), this, SLOT( close() ) );
	// Save new mode:
	_mode = MBsSWs_mode;
	// Close wait-message:
        waitmsgbox.stop();
	// Check for communication error:
	if (!ok)
		communicationError();
}


void EngineDialog::adjustments()
{
	bool ok = false;
	if (_mode == Adaptions_mode) return;
	// Show wait-message:
        myProgressbar waitmsgbox(0,tr("Switching to Adjustment Values... Please wait !"));
        waitmsgbox.start();
	// Save content settings:
	saveContentSettings();
	// Create, setup and insert new content-widget:
	_content_Adjustments = new CUcontent_Adjustments();
	setContentWidget(tr("Adjustments:"), _content_Adjustments);
	_content_Adjustments->show();
	ok = _content_Adjustments->setup(_SSMPdev);
	if (ok)
		connect(_content_Adjustments, SIGNAL( communicationError() ), this, SLOT( close() ) );
	// Save new mode:
	_mode = Adaptions_mode;
	// Close wait-message:
        waitmsgbox.close();
	// Check for communication error:
	if (!ok)
		communicationError();
}


void EngineDialog::systemoperationtests()
{
	bool ok = false;
	if (_mode == SysTests_mode) return;
	// Show wait-message:
        myProgressbar waitmsgbox(0,tr("Switching to System Tests... Please wait !"));
        waitmsgbox.start();
	// Save content settings:
	saveContentSettings();
	// Create, setup and insert new content-widget:
	CUcontent_sysTests *content_SysTests = new CUcontent_sysTests();
	setContentWidget(tr("System Operation Tests:"), content_SysTests);
	content_SysTests->show();
	ok = content_SysTests->setup(_SSMPdev);
	// Get notification, if internal error occures:
	if (ok)
		connect(content_SysTests, SIGNAL( error() ), this, SLOT( close() ) );
	// Save new mode:
	_mode = SysTests_mode;
	// Close wait-message:
        waitmsgbox.stop();
	// Check for communication error:
	if (!ok)
		communicationError();
}


void EngineDialog::clearMemory()
{
	bool ok = false;
	ClearMemoryDlg::CMresult_dt result;
	// Create "Clear Memory"-dialog:
	ClearMemoryDlg cmdlg(this, _SSMPdev, SSMprotocol::CMlevel_1);
	// Temporary disconnect from "communication error"-signal:
	disconnect(_SSMPdev, SIGNAL( commError() ), this, SLOT( communicationError() ));
	// Run "Clear Memory"-procedure:
	result = cmdlg.run();
	// Reconnect to "communication error"-signal:
	connect(_SSMPdev, SIGNAL( commError() ), this, SLOT( communicationError() ));
	// Check result:
	if ((result == ClearMemoryDlg::CMresult_success) && (_mode == Adaptions_mode))
	{
                myProgressbar waitmsgbox(0,tr("Reading Adjustment Values... Please wait !"));
                waitmsgbox.start();
		ok = _content_Adjustments->setup(_SSMPdev); // refresh adjustment values
                waitmsgbox.stop();
		if (!ok)
			communicationError();
	}
	else if (result == ClearMemoryDlg::CMresult_communicationError)
	{
		communicationError();
	}
	else if ((result == ClearMemoryDlg::CMresult_reconnectAborted) || (result == ClearMemoryDlg::CMresult_reconnectFailed))
	{
		close(); // exit engine control unit dialog
	}
}


void EngineDialog::saveContentSettings()
{
	if (_mode == MBsSWs_mode)
	{
		_content_MBsSWs->getMBSWselection(&_lastMBSWmetaList);
		_content_MBsSWs->getSettings(&_MBSWsettings);
	}
}

